本篇將會繼續咱有關Go語言函式的種種,今日介紹的是 :
所謂參數不定函式,指的就是一個函式可以接收數量不確定的參數,使用時機就是當你無法確認某個參數要接收的引數有多少個。
典型不定參數寫法,就是型別前面加三點...,這個點在這邊也有屬於它的名字,打包算符(pack package)
用來表示可接收不定數量的引數,不定數量也包括完全沒有引數。
func f(參數名稱...型別)
而它的作用實際上就是把所有符合該型別的引數都放進此參數名稱,打包成一個切片。
如下範例 :
package main
import "fmt"
func main() {
nums(10,99)
nums(100,990)
nums()
}
func nums(i...int) {
fmt.Println(i)
}
輸出結果 :
參數不定函式也可以有其他參數,但數量不定的一定要放在所有參數後面喔!!!
以下為錯誤範例 :
package main
import "fmt"
func main() {
nums(10,99,"Ricky")
nums(100,990, "Jack")
nums("Lily")
}
func nums(i...int, name string) {
fmt.Println(i, name)
}
正確寫法 :
package main
import "fmt"
func main() {
nums("Ricky",10,99)
nums("Jack",100,990)
nums("Lily")
}
func nums(name string, i...int) {
fmt.Println(name, i)
}
輸出結果:
就剛剛所說,不定參數函式,會將參數集結成切片,但如果直接將切片當引數傳入呢 ?
package main
import "fmt"
func main() {
i := []int{5, 10, 15}
nums(i) //傳入切片
}
func nums(i...int) {
fmt.Println(i)
}
答案是會產生錯誤 : []int型別不能傳給int型別參數
蛤 ? 這樣剛剛說會集結成切片是咋回事 ? 好,其實是參數不定函式是接收一連串不定數量的值,再轉成切片。
那麼這個案例怎麼玩 ? 我們可以用...,它在這叫做unpack operator,意思就是先將[]int解開再傳入,這樣等同傳入值 nums(5,10,15)。注意此...與參數不定函式的...意義不同。
package main
import "fmt"
func main() {
i := []int{5, 10, 15}
nums(i...) //傳入切片 解包算符unpack operator
}
func nums(i...int) {
fmt.Println(i)
}
到目前我們都式用具名函式居多,也就是有名字的且在package層宣告的函式,那還有一種沒有名稱的,叫做匿名函式(anonymous functions) 或稱函式常值(function literals)。
匿名函式 :
匿名函式可以搭配以下用途或功能 :
匿名函式 vs 具名函式,宣告上的差異就是 : 有無名字。
package main
import "fmt"
func main() {
//宣告匿名函式
func() {
fmt.Println("Hi~")
}() // 用()立即呼叫
}
關於那個小括號,稱為執行小括號(execution parenthese)。這對小括號會當場呼叫匿名函式執行它,謠傳給函式的引數必須寫在執行小括號。
就像這樣:
package main
import "fmt"
func main() {
name := "Ricky"
func(str string) {
fmt.Println("Hi~" + str)
}(name)
}
以上就是立即執行、且只能用一次的匿名函式,之後篇幅會介紹如何把它存在變數的不同運作方式。
範例 :
package main
import "fmt"
func main() {
// 定義匿名函數並將其指派給變數 add
add := func(x, y int) int {
return x + y
}
// 呼叫匿名函數
result := add(3, 5)
fmt.Printf("結果是:%d\n", result) //結果是 8
}
以上就是展示將匿名函式賦值給變數,再利用該變數來使用函式。
由匿名函式應用擴展到閉包的部分。
閉包,就是匿名函式的諸多形式之一,一般函式在離開某個函式的範圍後,就沒辦法繼續引用父函式的區域變數,但閉包可以。
一般匿名函式 :
package main
import "fmt"
func main() {
i := 0
increment := func() int {
i++
return i
}
fmt.Println(increment())
fmt.Println(increment())
i+=10
fmt.Println(increment())
}
結果 :
但是如果increment()是宣告在其他函式裡 :
package main
import "fmt"
func main() {
increment := incrementor() //接收傳回的函式
fmt.Println(increment())
fmt.Println(increment())
fmt.Println(increment())
}
func incrementor() func() int {
i := 0
return func() int {
i++
return i
}
}
這裡的 increment 就是語意閉包(lexical closure)或就簡稱閉包,因為這個函式包住了他所引用的外部變數。換句話說,閉包能記住父函式的變數,即便離開父函式的執行範圍
閉包可以記住外部變數的這個特性,我們可以加以利用。
一個倒數計數器的練習 :
package main
import "fmt"
func main() {
max:=10
increment := decrementor(max)
fmt.Println(increment())
fmt.Println(increment())
fmt.Println(increment())
fmt.Println(increment())
fmt.Println(increment())
fmt.Println(increment())
fmt.Println(increment())
fmt.Println(increment())
fmt.Println(increment())
fmt.Println(increment())
}
func decrementor(i int) func() int {
return func() int {
if i > 0 {
i--
}
return i
}
}
以上就是本篇的整理~~